<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>基于SpringBoot与Vue的大文件分片上传与流式下载 | LenlBlog</title><meta name="author" content="Lenl,lenl412@163.com"><meta name="copyright" content="Lenl"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="ffffff"><meta name="description" content="记录一下实现分片上传与流式下载的过程">
<meta property="og:type" content="article">
<meta property="og:title" content="基于SpringBoot与Vue的大文件分片上传与流式下载">
<meta property="og:url" content="https://lienle.gitee.io/notes/chunkFile/index.html">
<meta property="og:site_name" content="LenlBlog">
<meta property="og:description" content="记录一下实现分片上传与流式下载的过程">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png">
<meta property="article:published_time" content="2023-05-13T13:57:28.000Z">
<meta property="article:modified_time" content="2023-05-13T15:27:01.872Z">
<meta property="article:author" content="Lenl">
<meta property="article:tag" content="SpringBoot">
<meta property="article:tag" content="Vue">
<meta property="article:tag" content="分片上传">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png"><link rel="shortcut icon" href="/img/lenl.png"><link rel="canonical" href="https://lienle.gitee.io/notes/chunkFile/index.html"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><meta name="baidu-site-verification" content="codeva-6HME93uF43"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?629608ec0c773bd9f96cb72389693ab9";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容：${query}","hits_stats":"共找到 ${hits} 篇文章"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  dateSuffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: {"limitCount":50,"languages":{"author":"作者: Lenl","link":"链接: ","source":"来源: LenlBlog","info":"著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。"}},
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: true,
  islazyload: true,
  isAnchor: false,
  percent: {
    toc: true,
    rightside: false,
  }
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: '基于SpringBoot与Vue的大文件分片上传与流式下载',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2023-05-13 23:27:01'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
    win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
      const link = document.createElement('link')
      link.rel = 'stylesheet'
      link.href = url
      if (id) link.id = id
      link.onerror = reject
      link.onload = link.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        link.onload = link.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(link)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', 'ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script></head><body><!--include ./fullpage-loading.pug--><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><div class="wizard-scene"><div class="wizard-objects"><div class="wizard-square"></div><div class="wizard-circle"></div><div class="wizard-triangle"></div></div><div class="wizard"><div class="wizard-body"></div><div class="wizard-right-arm"><div class="wizard-right-hand"></div></div><div class="wizard-left-arm"><div class="wizard-left-hand"></div></div><div class="wizard-head"><div class="wizard-beard"></div><div class="wizard-face"><div class="wizard-adds"></div></div><div class="wizard-hat"><div class="wizard-hat-of-the-hat"></div><div class="wizard-four-point-star --first"></div><div class="wizard-four-point-star --second"></div><div class="wizard-four-point-star --third"></div></div></div></div></div></div><script>const preloader = {
  endLoading: () => {
    document.body.style.overflow = '';
    document.getElementById('loading-box').classList.add("loaded")
  },
  initLoading: () => {
    document.body.style.overflow = 'hidden';
    document.getElementById('loading-box').classList.remove("loaded")
  }
}

preloader.initLoading()
window.addEventListener('load',()=> { preloader.endLoading() })
//避免加载时间过长
setTimeout(function(){preloader.endLoading();}, 3000);

if (false) {
  document.addEventListener('pjax:send', () => { preloader.initLoading() })
  document.addEventListener('pjax:complete', () => { preloader.endLoading() })
}</script><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src= "/img/hexo_loading.gif" data-lazy-src="/img/lenl.png" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">17</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">25</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">8</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 存档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 分享</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/collect/"><i class="fa-fw fas fa-book"></i><span> 大佬们の干货</span></a></li><li><a class="site-page child" href="/resources/"><i class="fa-fw fab fa-dropbox"></i><span> 屯屯鼠の资源</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg fixed" id="page-header" style="background-image: url('https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png')"><nav id="nav"><span id="blog-info"><a href="/" title="LenlBlog"><img class="site-icon" src= "/img/hexo_loading.gif" data-lazy-src="/img/lenl.png"/><span class="site-name">LenlBlog</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 存档</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 分享</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/collect/"><i class="fa-fw fas fa-book"></i><span> 大佬们の干货</span></a></li><li><a class="site-page child" href="/resources/"><i class="fa-fw fab fa-dropbox"></i><span> 屯屯鼠の资源</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">基于SpringBoot与Vue的大文件分片上传与流式下载</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-05-13T13:57:28.000Z" title="发表于 2023-05-13 21:57:28">2023-05-13</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-05-13T15:27:01.872Z" title="更新于 2023-05-13 23:27:01">2023-05-13</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E7%BC%96%E7%A8%8B%E9%9A%8F%E8%AE%B0/">编程随记</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">4.9k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>23分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="基于SpringBoot与Vue的大文件分片上传与流式下载"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span><span class="post-meta-separator">|</span><span class="post-meta-commentcount"><i class="far fa-comments fa-fw post-meta-icon"></i><span class="post-meta-label">评论数:</span><a href="/notes/chunkFile/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/notes/chunkFile/" itemprop="commentCount"><i class="fa-solid fa-spinner fa-spin"></i></span></a></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><div class="note info simple"><p>最近需要实现一个往服务器上传文件（上G级别），并能够下载的类似云存储的功能。</p>
<p>这涉及到文件的分片上传与下载，在此记录一下实现过程。</p>
</div>
<h2 id="实现技术">实现技术</h2>
<ul class="lvl-0">
<li class="lvl-2">
<p>前端</p>
<p>前端是使用Vue2+Element UI 做的界面实现；</p>
</li>
<li class="lvl-2">
<p>后端</p>
<p>后端是使用SpringBoot 2.7 做的API服务，集成SpringSecurity做了权限控制</p>
</li>
</ul>
<h2 id="文件上传">文件上传</h2>
<h3 id="分析">分析</h3>
<p>在这个系统之前的功能里也有需要进行图片上传的功能，但是图片体积普遍较小，会限制在10MB以内。彼时，我为了方便采用的是将其数据Base64编码成字符串传到后端，后端接收后还原为byte数组，存储即可。由于数据量小，这一方式并未出现任何问题。</p>
<p>但是现在的文件体量来到了GB级别，那必然不可能再编成字符串了。大文件就必然要考虑切片上传，因此整理了一下思路：</p>
<ul class="lvl-0">
<li class="lvl-2">
<p>首先，前端获取文件，将其切片，并计算其哈希值准备上传；</p>
</li>
<li class="lvl-2">
<p>前端上传每一片携带当前文件的哈希值，拱后端识别和存储；</p>
</li>
<li class="lvl-2">
<p>后端将切片编序存储在哈希值对应的文件夹里；</p>
</li>
<li class="lvl-2">
<p>前端最后发送一个合并请求，携带业务数据和文件哈希；</p>
</li>
<li class="lvl-2">
<p>后端接收合并请求后返回响应，并开启线程进行异步合并。</p>
</li>
<li class="lvl-2">
<p>其中，上传切片前请求后端判断一次该哈希是否已上传，如果已上传只存储业务信息，将文件路径指向重复的文件即可完成秒传。</p>
</li>
</ul>
<p>这个思路看起来还行，没什么问题，那我们就甩开膀子开干~</p>
<h3 id="前端实现">前端实现</h3>
<p>我准备把这个上传界面做成一个dialog组件，由主界面点开后打开dialog，上传完毕后关闭并刷新主界面的文件列表。实现如下：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">el-dialog</span> <span class="attr">title</span>=<span class="string">&quot;添加资料&quot;</span> <span class="attr">append-to-body</span> <span class="attr">:before-close</span>=<span class="string">&quot;close&quot;</span> <span class="attr">center</span> <span class="attr">:close-on-click-modal</span>=<span class="string">&quot;false&quot;</span> </span></span><br><span class="line"><span class="tag">    <span class="attr">:show-close</span>=<span class="string">&quot;!uploading&quot;</span> <span class="attr">:visible.sync</span>=<span class="string">&quot;visible&quot;</span> <span class="attr">width</span>=<span class="string">&quot;850px&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">el-form</span> <span class="attr">:model</span>=<span class="string">&quot;resForm&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;ResForm&quot;</span> <span class="attr">size</span>=<span class="string">&quot;mini&quot;</span> <span class="attr">label-width</span>=<span class="string">&quot;180px&quot;</span> <span class="attr">label-position</span>=<span class="string">&quot;right&quot;</span> <span class="attr">:rules</span>=<span class="string">&quot;rules&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width:90%&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-form-item</span> <span class="attr">label</span>=<span class="string">&quot;资料名称：&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;name&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">el-input</span> <span class="attr">v-model</span>=<span class="string">&quot;resForm.name&quot;</span>  <span class="attr">placeholder</span>=<span class="string">&quot;请输入资料名称&quot;</span> <span class="attr">:maxlength</span>=<span class="string">&quot;50&quot;</span> <span class="attr">:disabled</span>=<span class="string">&quot;uploading&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-input</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">el-form-item</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-form-item</span> <span class="attr">label</span>=<span class="string">&quot;资料说明：&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;notes&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">el-input</span> <span class="attr">v-model</span>=<span class="string">&quot;resForm.notes&quot;</span> <span class="attr">type</span>=<span class="string">&quot;textarea&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;请输入资料说明&quot;</span> <span class="attr">:maxlength</span>=<span class="string">&quot;100&quot;</span> <span class="attr">:disabled</span>=<span class="string">&quot;uploading&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-input</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">el-form-item</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-form-item</span> <span class="attr">label</span>=<span class="string">&quot;上传资料文件：&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">el-upload</span>  <span class="attr">ref</span>=<span class="string">&quot;upload&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:file-list</span>=<span class="string">&quot;fileList&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:on-remove</span>=<span class="string">&quot;handleRemove&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:on-change</span>=<span class="string">&quot;picChange&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:multiple</span>=<span class="string">&quot;false&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:auto-upload</span>=<span class="string">&quot;true&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">action</span>=<span class="string">&quot;#&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:before-upload</span>=<span class="string">&quot;beforeUpload&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">el-button</span> <span class="attr">size</span>=<span class="string">&quot;mini&quot;</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span>  &gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">&quot;el-icon-document-add&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span></span><br><span class="line">                    <span class="symbol">&amp;nbsp;</span></span><br><span class="line">                    选择文件</span><br><span class="line">                <span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">slot</span>=<span class="string">&quot;tip&quot;</span> <span class="attr">class</span>=<span class="string">&quot;el-upload__tip&quot;</span>&gt;</span>请上传文件，文件不超过1GB<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">el-upload</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">el-button</span></span></span><br><span class="line"><span class="tag">                <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:disabled</span>=<span class="string">&quot;fileList.length === 0 || !finishSlice&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">:loading</span>=<span class="string">&quot;uploading&quot;</span></span></span><br><span class="line"><span class="tag">                <span class="attr">style</span>=<span class="string">&quot;margin-top: 16px&quot;</span></span></span><br><span class="line"><span class="tag">                @<span class="attr">click</span>=<span class="string">&quot;handleUpload&quot;</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">&quot;el-icon-upload&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span></span><br><span class="line">                    <span class="symbol">&amp;nbsp;</span></span><br><span class="line">                &#123;&#123; uploading ? &quot;上传中~&quot; : &quot;开始上传&quot; &#125;&#125;</span><br><span class="line">                <span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">el-divider</span>&gt;</span><span class="tag">&lt;/<span class="name">el-divider</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;progContainer&quot;</span>  <span class="attr">v-if</span>=<span class="string">&quot;showSliceProgress&quot;</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">el-tag</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span> <span class="attr">size</span>=<span class="string">&quot;mini&quot;</span> <span class="attr">plain</span>&gt;</span>切片进度：<span class="tag">&lt;/<span class="name">el-tag</span>&gt;</span> <span class="symbol">&amp;nbsp;</span><span class="symbol">&amp;nbsp;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">el-progress</span> <span class="attr">:percentage</span>=<span class="string">&quot;Math.round(sliceProgress/sliceCount*100)&quot;</span> <span class="attr">:stroke-width</span>=<span class="string">&quot;20&quot;</span> <span class="attr">class</span>=<span class="string">&quot;prog&quot;</span></span></span><br><span class="line"><span class="tag">                            <span class="attr">:status</span>=<span class="string">&quot;sliceProgress===sliceCount ? &#x27;success&#x27;:&#x27;warning&#x27;&quot;</span> /&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                </span><br><span class="line">                <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-if</span>=<span class="string">&quot;showProgress&quot;</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">el-tag</span> <span class="attr">type</span>=<span class="string">&quot;success&quot;</span> <span class="attr">size</span>=<span class="string">&quot;mini&quot;</span> <span class="attr">plain</span>&gt;</span>上传进度：<span class="tag">&lt;/<span class="name">el-tag</span>&gt;</span> <span class="symbol">&amp;nbsp;</span><span class="symbol">&amp;nbsp;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">el-progress</span> <span class="attr">:percentage</span>=<span class="string">&quot;Math.round(finishCount/sliceCount*100)&quot;</span> <span class="attr">class</span>=<span class="string">&quot;prog&quot;</span></span></span><br><span class="line"><span class="tag">                            <span class="attr">:status</span>=<span class="string">&quot;finishCount===sliceCount ? &#x27;success&#x27;:&#x27;warning&#x27;&quot;</span> /&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">el-form-item</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">el-form</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">el-dialog</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">import</span> <span class="title class_">SparkMD5</span> <span class="keyword">from</span> <span class="string">&#x27;spark-md5&#x27;</span></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="attr">name</span>:<span class="string">&#x27;AddResource&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">    <span class="attr">props</span>:&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//控制dialog是否可见</span></span></span><br><span class="line"><span class="language-javascript">        <span class="attr">visible</span>:&#123;<span class="attr">type</span>:<span class="title class_">Boolean</span>,<span class="attr">default</span>:<span class="literal">false</span>&#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//刷新主界面的列表</span></span></span><br><span class="line"><span class="language-javascript">        <span class="attr">flushList</span>:<span class="title class_">Function</span>,</span></span><br><span class="line"><span class="language-javascript">    &#125;,</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">data</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">loading</span>:<span class="literal">false</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">resForm</span>:&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">name</span>:<span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">notes</span>:<span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">rules</span>:&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">name</span>:[&#123;<span class="attr">required</span>:<span class="literal">true</span>,<span class="attr">message</span>:<span class="string">&quot;资料名称不能为空&quot;</span>,<span class="attr">trigger</span>:<span class="string">&#x27;blur&#x27;</span>&#125;],</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">notes</span>:[&#123;<span class="attr">required</span>:<span class="literal">true</span>,<span class="attr">message</span>:<span class="string">&quot;资料描述不能为空&quot;</span>,<span class="attr">trigger</span>:<span class="string">&#x27;blur&#x27;</span>&#125;],</span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// #region 文件上传变量</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">fileList</span>:[],</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">uploading</span>:<span class="literal">false</span>,<span class="comment">//是否正在上传</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">finishSlice</span>:<span class="literal">false</span>,<span class="comment">//分片完成情况</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">finishCount</span>:<span class="number">0</span>,<span class="comment">//分片完成数量</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">showProgress</span>:<span class="literal">false</span>,<span class="comment">//展示上传进度条</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">sliceCount</span>:<span class="number">0</span>,<span class="comment">//切片数量</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">sliceProgress</span>:<span class="number">0</span>,<span class="comment">//切片进度条</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">errorCount</span>:<span class="number">0</span>,<span class="comment">//上传失败数量</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">showSliceProgress</span>:<span class="literal">false</span>,<span class="comment">//展示切片进度条</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">fileChunkList</span>:[],<span class="comment">//切片列表</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">sendCount</span>:<span class="number">0</span>,<span class="comment">//发送的切片数量,</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">fileType</span>:<span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">filename</span>:<span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">hash</span>:<span class="string">&quot;&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// #endregion </span></span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;,</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">mounted</span>(<span class="params"></span>)&#123;&#125;,</span></span><br><span class="line"><span class="language-javascript">    <span class="attr">methods</span>:&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">reset</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">$refs</span>.<span class="property">ResForm</span>.<span class="title function_">resetFields</span>()</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileList</span>=[]</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">uploading</span>=<span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">finishSlice</span>=<span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">finishCount</span>=<span class="number">0</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">showProgress</span>=<span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">errorCount</span>=<span class="number">0</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">showSliceProgress</span>=<span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileChunkList</span>=[]</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">sendCount</span>=<span class="number">0</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileType</span>=<span class="string">&#x27;&#x27;</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">filename</span>=<span class="string">&#x27;&#x27;</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">hash</span></span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">close</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//关闭前重置变量</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="title function_">reset</span>()</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//调用关闭</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.$emit(<span class="string">&#x27;changeVisible&#x27;</span>,<span class="literal">false</span>)</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">picChange</span>(<span class="params">file,fileList</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (file.<span class="property">size</span>&gt;<span class="number">1024</span>*<span class="number">1024</span>*<span class="number">10240</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">var</span> index = fileList.<span class="title function_">indexOf</span>(file);</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span>(index&gt;=<span class="number">0</span>)</span></span><br><span class="line"><span class="language-javascript">                fileList.<span class="title function_">splice</span>(index, <span class="number">1</span>);</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">warning</span>(<span class="string">&#x27;文件必须小于10GB！&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span>(fileList.<span class="property">length</span>&gt;<span class="number">1</span>)</span></span><br><span class="line"><span class="language-javascript">                fileList.<span class="title function_">splice</span>(<span class="number">0</span>,<span class="number">1</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileList</span> = fileList;</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//上传前文件切片</span></span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">beforeUpload</span>(<span class="params">file</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">info</span>(<span class="string">&quot;开始文件切片&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 显示切片进度条</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">showSliceProgress</span> = <span class="literal">true</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 文件添加到文件列表 这里只展示单文件上传</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileList</span> = [file];</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 一些参数的初始化</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileChunkList</span> = [];</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">finishSlice</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">finishCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">sliceProgress</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">showProgress</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">sliceCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">errorCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">() =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 初始化md5工具对象</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">const</span> spark = <span class="keyword">new</span> <span class="title class_">SparkMD5</span>.<span class="title class_">ArrayBuffer</span>();</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 用于读取文件计算md5</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">const</span> fileReader = <span class="keyword">new</span> <span class="title class_">FileReader</span>();</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 这里是依据.来对文件和类型进行分割</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">let</span> fileInfo = file.<span class="property">name</span>.<span class="title function_">split</span>(<span class="string">&quot;.&quot;</span>)</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">filename</span> = fileInfo[<span class="number">0</span>];</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 最后一个.之前的内容都应该认定为文件名称</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (fileInfo.<span class="property">length</span> &gt; <span class="number">1</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">filetype</span> = fileInfo[fileInfo.<span class="property">length</span> - <span class="number">1</span>];</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt; fileInfo.<span class="property">length</span> - <span class="number">1</span>; i++) &#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">filename</span> = <span class="variable language_">this</span>.<span class="property">filename</span> + <span class="string">&quot;.&quot;</span> + fileInfo[i];</span></span><br><span class="line"><span class="language-javascript">                    &#125;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 这里开始做切片</span></span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 设置切片大小 可以根据实际情况设置</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">const</span> chunkSize = <span class="number">1024</span> * <span class="number">1024</span> * <span class="number">1</span>;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 计算出切片数量</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">sliceCount</span> = <span class="title class_">Math</span>.<span class="title function_">ceil</span>(file.<span class="property">size</span> / chunkSize);</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">let</span> curChunk = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 切片操作的实际方法【定义】</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">const</span> <span class="title function_">sliceNext</span> = (<span class="params"></span>) =&gt; &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 使用slice方法进行文件切片</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">const</span> chunkFile = file.<span class="title function_">slice</span>(curChunk, curChunk + chunkSize);</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 读取当前切片文件流【这里会触发onload方法】</span></span></span><br><span class="line"><span class="language-javascript">                fileReader.<span class="title function_">readAsArrayBuffer</span>(chunkFile);</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 加入切片列表</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">fileChunkList</span>.<span class="title function_">push</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 切片文件信息</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">chunk</span>: chunkFile,</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 文件名</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">filename</span>: <span class="variable language_">this</span>.<span class="property">filename</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 分片索引 这里直接借助sliceProgress来实现</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">seq</span>: <span class="variable language_">this</span>.<span class="property">sliceProgress</span> + <span class="number">1</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 文件类型</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">type</span>: <span class="variable language_">this</span>.<span class="property">filetype</span>,</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 状态信息 用于标识是否上传成功</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="attr">status</span>: <span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">                &#125;);</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 切片完成变量自增</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">sliceProgress</span>++;</span></span><br><span class="line"><span class="language-javascript">                &#125;;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 进入方法需要进行首次切片操作</span></span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">sliceNext</span>();</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 读取文件流时会触发onload方法</span></span></span><br><span class="line"><span class="language-javascript">                fileReader.<span class="property">onload</span> = <span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 将文件流加入计算md5</span></span></span><br><span class="line"><span class="language-javascript">                    spark.<span class="title function_">append</span>(e.<span class="property">target</span>.<span class="property">result</span>);</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 修改切片位移</span></span></span><br><span class="line"><span class="language-javascript">                    curChunk += chunkSize;</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 说明还没到达最后一个切片 继续切</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">sliceProgress</span> &lt; <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="title function_">sliceNext</span>();</span></span><br><span class="line"><span class="language-javascript">                    &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="comment">// 说明切片完成了</span></span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">finishSlice</span> = <span class="literal">true</span>;</span></span><br><span class="line"><span class="language-javascript">                        <span class="comment">// 读取文件hash值</span></span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">hash</span> = spark.<span class="title function_">end</span>();</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">success</span>(<span class="string">&quot;文件分片完成&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                        <span class="comment">// 将哈希值作为其中一个属性 写入到分片列表中</span></span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">fileChunkList</span>.<span class="title function_">forEach</span>(<span class="function">(<span class="params">content</span>) =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                            content.<span class="property">hash</span> = <span class="variable language_">this</span>.<span class="property">hash</span>;</span></span><br><span class="line"><span class="language-javascript">                        &#125;)</span></span><br><span class="line"><span class="language-javascript">                    &#125;</span></span><br><span class="line"><span class="language-javascript">                &#125;;</span></span><br><span class="line"><span class="language-javascript">            &#125;)</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//开始执行上传切片逻辑</span></span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">startUpload</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">() =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> <span class="title function_">next</span> = (<span class="params"></span>) =&gt; &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 递归出口 分片上传完毕</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">finishCount</span> + <span class="variable language_">this</span>.<span class="property">errorCount</span> &gt;= <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span>;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 记录当前遍历位置</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">let</span> cur = <span class="variable language_">this</span>.<span class="property">sendCount</span>++;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 说明越界了 直接退出</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (cur &gt;= <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span>;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 获取分片信息</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">let</span> content = <span class="variable language_">this</span>.<span class="property">fileChunkList</span>[cur];</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 已经上传过了 直接跳过【可用于断点续传】</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (content.<span class="property">status</span> === <span class="literal">true</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">finishCount</span> + <span class="variable language_">this</span>.<span class="property">errorCount</span> &lt; <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="title function_">next</span>();</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">return</span>;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 开始填充上传数据 这里需要使用FormData来存储信息</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> formData = <span class="keyword">new</span> <span class="title class_">FormData</span>();</span></span><br><span class="line"><span class="language-javascript">            formData.<span class="title function_">append</span>(<span class="string">&quot;file&quot;</span>, content.<span class="property">chunk</span>);</span></span><br><span class="line"><span class="language-javascript">            formData.<span class="title function_">append</span>(<span class="string">&quot;hash&quot;</span>, content.<span class="property">hash</span>);</span></span><br><span class="line"><span class="language-javascript">            formData.<span class="title function_">append</span>(<span class="string">&quot;filename&quot;</span>, content.<span class="property">filename</span>);</span></span><br><span class="line"><span class="language-javascript">            formData.<span class="title function_">append</span>(<span class="string">&quot;seq&quot;</span>, content.<span class="property">seq</span>);</span></span><br><span class="line"><span class="language-javascript">            formData.<span class="title function_">append</span>(<span class="string">&quot;type&quot;</span>, content.<span class="property">type</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 开始上传</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">$http</span>.<span class="title function_">post</span>(<span class="string">&quot;res/upload&quot;</span>, formData).<span class="title function_">then</span>(<span class="function">(<span class="params">res</span>) =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 接收回调信息</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">const</span> data = res.<span class="property">data</span>;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (data.<span class="property">success</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 成功计数 并设置分片上传状态</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">finishCount</span> += <span class="number">1</span>;</span></span><br><span class="line"><span class="language-javascript">                content.<span class="property">status</span> = <span class="literal">true</span>;</span></span><br><span class="line"><span class="language-javascript">                &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 失败计数</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">errorCount</span> += <span class="number">1</span>;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 说明完成最后一个分片上传但上传期间出现错误</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">errorCount</span> !== <span class="number">0</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">errorCount</span> + <span class="variable language_">this</span>.<span class="property">finishCount</span> === <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">error</span>(<span class="string">&quot;上传发生错误，请重传&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">showProgress</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">uploading</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 说明还有分片未上传 需要继续递归</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">finishCount</span> + <span class="variable language_">this</span>.<span class="property">errorCount</span> &lt; <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">next</span>();</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 说明所有分片上传成功了 发起合并操作</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">finishCount</span> === <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="title function_">merge</span>();</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">error</span> =&gt;</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 对于图中发生的错误需要捕获并记录</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">errorCount</span> += <span class="number">1</span>;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">errorCount</span> !== <span class="number">0</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">errorCount</span> + <span class="variable language_">this</span>.<span class="property">finishCount</span> === <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">error</span>(<span class="string">&quot;上传发生错误，请重传&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">showProgress</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">uploading</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 当前分片上传失败不应影响下面的分片</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">finishCount</span> + <span class="variable language_">this</span>.<span class="property">errorCount</span> &lt; <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">next</span>();</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">console</span>.<span class="title function_">error</span>(error)</span></span><br><span class="line"><span class="language-javascript">            &#125;)</span></span><br><span class="line"><span class="language-javascript">            &#125;;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 只允许同时10个任务在等待</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">while</span> (<span class="variable language_">this</span>.<span class="property">sendCount</span> &lt; <span class="number">10</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">sendCount</span> &lt; <span class="variable language_">this</span>.<span class="property">sliceCount</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="title function_">next</span>();</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;);</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//文件合并</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">async</span> <span class="title function_">merge</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">success</span>(<span class="string">&#x27;上传完成，等待服务器合并文件中~&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 发起合并请求 传入文件hash值、文件类型、文件名 </span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> &#123;<span class="attr">data</span>:res&#125;= <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">$http</span>.<span class="title function_">post</span>(<span class="string">&quot;res/merge&quot;</span>, &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">name</span>:<span class="variable language_">this</span>.<span class="property">resForm</span>.<span class="property">name</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">notes</span>:<span class="variable language_">this</span>.<span class="property">resForm</span>.<span class="property">notes</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">hash</span>: <span class="variable language_">this</span>.<span class="property">hash</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">type</span>: <span class="variable language_">this</span>.<span class="property">filetype</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">filename</span>: <span class="variable language_">this</span>.<span class="property">filename</span></span></span><br><span class="line"><span class="language-javascript">            &#125;)</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (res.<span class="property">success</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">success</span>(<span class="string">&#x27;资料已完成上传！&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//初始化参数，关闭上传界面</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="title function_">close</span>()</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="title function_">flushList</span>()</span></span><br><span class="line"><span class="language-javascript">            &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">message</span>.<span class="title function_">error</span>(<span class="string">&#x27;文件合并失败！上传失败。&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">console</span>.<span class="title function_">error</span>(res.<span class="property">msg</span>)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">uploading</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//取消文件</span></span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">handleRemove</span>(<span class="params">file</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> index = <span class="variable language_">this</span>.<span class="property">fileList</span>.<span class="title function_">indexOf</span>(file);</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> newFileList = <span class="variable language_">this</span>.<span class="property">fileList</span>.<span class="title function_">slice</span>();</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">hash</span> = <span class="string">&quot;&quot;</span>;</span></span><br><span class="line"><span class="language-javascript">            newFileList.<span class="title function_">splice</span>(index, <span class="number">1</span>);</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileList</span> = newFileList;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">// 取消之后需要进行相关变量的重新初始化</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">fileChunkList</span> = [];</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">finishSlice</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">finishCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">sliceProgress</span>= <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">showProgress</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">showSliceProgress</span>=<span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">sliceCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">errorCount</span>= <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//执行上传</span></span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">handleUpload</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">finishSlice</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">warning</span>(<span class="string">&quot;文件切片中，请稍等~&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span>;</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//检查参数以及进行询问</span></span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">$refs</span>.<span class="property">ResForm</span>.<span class="title function_">validate</span>(<span class="keyword">async</span> valid=&gt;&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span>(valid)&#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">const</span> confirmresult=<span class="keyword">await</span> <span class="variable language_">this</span>.$confirm(<span class="string">&#x27;将要添加资源文件，请确定是否继续？&#x27;</span>,<span class="string">&#x27;提示&#x27;</span>,&#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="attr">confirmButtonText</span>:<span class="string">&#x27;确定&#x27;</span>,<span class="attr">cancelButtonText</span>:<span class="string">&#x27;取消&#x27;</span>,<span class="attr">type</span>:<span class="string">&#x27;warning&#x27;</span></span></span><br><span class="line"><span class="language-javascript">                    &#125;)</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">if</span>(confirmresult!==<span class="string">&#x27;confirm&#x27;</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">info</span>(<span class="string">&#x27;操作已取消&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                    &#125;</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 进度条变更</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="variable language_">this</span>.<span class="property">showSliceProgress</span> = <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">                    <span class="comment">// 先检查是否已经上传过</span></span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">const</span>&#123;<span class="attr">data</span>:res&#125;=<span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">$http</span>.<span class="title function_">get</span>(<span class="string">&quot;res/check&quot;</span>,&#123;<span class="attr">params</span>:&#123;<span class="attr">hash</span>:<span class="variable language_">this</span>.<span class="property">hash</span>&#125;&#125;) </span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">if</span>(!res.<span class="property">success</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">error</span>(<span class="string">&#x27;检查文件失败&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">console</span>.<span class="title function_">error</span>(res.<span class="property">msg</span>)</span></span><br><span class="line"><span class="language-javascript">                        <span class="keyword">return</span>;</span></span><br><span class="line"><span class="language-javascript">                    &#125;</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">if</span> (res.<span class="property">data</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">warning</span>(<span class="string">&#x27;文件已存在，开始进行秒传&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                        <span class="comment">// TODO 秒传逻辑</span></span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="title function_">fastUpload</span>()</span></span><br><span class="line"><span class="language-javascript">                    &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                        <span class="comment">// 开始上传逻辑 相关变量状态更迭</span></span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">uploading</span> = <span class="literal">true</span>;</span></span><br><span class="line"><span class="language-javascript">                        <span class="comment">// 这里主要是服务于断点续传 避免重复上传已成功分块</span></span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">sliceCount</span> -= <span class="variable language_">this</span>.<span class="property">finishCount</span>;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">errorCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">finishCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">sendCount</span> = <span class="number">0</span>;</span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="property">showProgress</span> = <span class="literal">true</span>;</span></span><br><span class="line"><span class="language-javascript">                        <span class="comment">// 调用上面写好的上传逻辑</span></span></span><br><span class="line"><span class="language-javascript">                        <span class="variable language_">this</span>.<span class="title function_">startUpload</span>();</span></span><br><span class="line"><span class="language-javascript">                    &#125;</span></span><br><span class="line"><span class="language-javascript">                &#125;<span class="keyword">else</span>&#123;</span></span><br><span class="line"><span class="language-javascript">                    <span class="keyword">return</span> <span class="literal">false</span>;</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;)</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//秒传</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">async</span> <span class="title function_">fastUpload</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">uploading</span> = <span class="literal">true</span>;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> &#123;<span class="attr">data</span>:res&#125;=<span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">$http</span>.<span class="title function_">get</span>(<span class="string">&#x27;res/fast&#x27;</span>,&#123;<span class="attr">params</span>:&#123;<span class="attr">hash</span>:<span class="variable language_">this</span>.<span class="property">hash</span>,<span class="attr">name</span>:<span class="variable language_">this</span>.<span class="property">resForm</span>.<span class="property">name</span>,<span class="attr">notes</span>:<span class="variable language_">this</span>.<span class="property">resForm</span>.<span class="property">notes</span>&#125;&#125;)</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span>(res.<span class="property">success</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">success</span>(<span class="string">&#x27;秒传已完成~操作成功！&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="title function_">close</span>()</span></span><br><span class="line"><span class="language-javascript">            &#125;<span class="keyword">else</span>&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">error</span>(<span class="string">&#x27;操作失败&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">console</span>.<span class="title function_">error</span>(res.<span class="property">msg</span>)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">uploading</span>=<span class="literal">false</span></span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;,</span></span><br><span class="line"><span class="language-javascript">&#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css"><span class="selector-class">.prog</span>&#123;</span></span><br><span class="line"><span class="language-css">    <span class="attribute">width</span>: <span class="number">450px</span>;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css"><span class="selector-class">.progContainer</span>&#123;</span></span><br><span class="line"><span class="language-css">    <span class="attribute">display</span>: flex;</span></span><br><span class="line"><span class="language-css">    justify-self: start;</span></span><br><span class="line"><span class="language-css">&#125;</span></span><br><span class="line"><span class="language-css"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>这样组件就准备好了，然后在主界面进行调用：</p>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="comment">&lt;!--调用组件--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">add-resource</span> <span class="attr">ref</span>=<span class="string">&quot;AddResource&quot;</span></span></span><br><span class="line"><span class="tag"><span class="attr">:visible</span>=<span class="string">&quot;addResourceVisible&quot;</span></span></span><br><span class="line"><span class="tag"><span class="attr">:flushList</span>=<span class="string">&quot;getResourceList&quot;</span></span></span><br><span class="line"><span class="tag">@<span class="attr">changeVisible</span>=<span class="string">&quot;changeAddResourceVisible&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">add-resource</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">export</span> <span class="keyword">default</span>&#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">data</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">return</span>&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">addResourceVisible</span>:<span class="literal">false</span>,</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;,</span></span><br><span class="line"><span class="language-javascript">    <span class="attr">methods</span>:&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//切换是否可见</span></span></span><br><span class="line"><span class="language-javascript">        <span class="title function_">changeAddResourceVisible</span>(<span class="params">val</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">addResourceVisible</span>=val</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//获取资源列表</span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">async</span> <span class="title function_">getResourceList</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//...业务逻辑</span></span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">&#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="后端实现">后端实现</h3>
<p>请求主要在组件里，需要实现的接口如下：</p>
<ul class="lvl-0">
<li class="lvl-2">
<p>判断哈希是否重复接口</p>
</li>
<li class="lvl-2">
<p>接收切片接口</p>
</li>
<li class="lvl-2">
<p>合并切片接口</p>
</li>
<li class="lvl-2">
<p>秒传接口</p>
</li>
</ul>
<p>首先是判断哈希是否重复：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//controller</span></span><br><span class="line"><span class="comment">//检查哈希重复</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/check&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ResultMsg&lt;Boolean&gt; <span class="title function_">check</span><span class="params">(String hash)</span>&#123;</span><br><span class="line">    AssertUtil.hasText(hash,<span class="string">&quot;缺少参数&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> ResultMsg.success(resourcesService.check(hash));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//service实现</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> Boolean <span class="title function_">check</span><span class="params">(String hash)</span> &#123;</span><br><span class="line">    QueryWrapper&lt;Resources&gt; wrapper=<span class="keyword">new</span> <span class="title class_">QueryWrapper</span>&lt;&gt;();</span><br><span class="line">    <span class="comment">//我这里是检查未删除的，因为已删除的文件不存在，也就无法秒传</span></span><br><span class="line">    wrapper.eq(<span class="string">&quot;hash&quot;</span>,hash).ne(<span class="string">&quot;state&quot;</span>,Resources.STATE_DELETE);</span><br><span class="line">    <span class="type">int</span> <span class="variable">count</span> <span class="operator">=</span> <span class="built_in">super</span>.count(wrapper);</span><br><span class="line">    <span class="keyword">return</span> count&gt;<span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>然后是接收切片：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//controller</span></span><br><span class="line"><span class="comment">//上传分片</span></span><br><span class="line"><span class="meta">@PostMapping(&quot;/upload&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ResultMsg&lt;Boolean&gt; <span class="title function_">uploadSlice</span><span class="params">(<span class="meta">@RequestParam(value = &quot;file&quot;)</span> MultipartFile file,</span></span><br><span class="line"><span class="params">                                      <span class="meta">@RequestParam(value = &quot;hash&quot;)</span> String hash,</span></span><br><span class="line"><span class="params">                                      <span class="meta">@RequestParam(value = &quot;filename&quot;)</span> String filename,</span></span><br><span class="line"><span class="params">                                      <span class="meta">@RequestParam(value = &quot;seq&quot;)</span> Integer seq,</span></span><br><span class="line"><span class="params">                                      <span class="meta">@RequestParam(value = &quot;type&quot;)</span> String type)</span>&#123;</span><br><span class="line">    resourcesService.uploadSlice(file,hash,filename,seq,type);</span><br><span class="line">    <span class="keyword">return</span> ResultMsg.success(<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//service实现</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">uploadSlice</span><span class="params">(MultipartFile file, String hash, String filename, Integer seq, String type)</span> &#123;</span><br><span class="line">    RandomAccessFile raf=<span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">try</span>&#123;</span><br><span class="line">        <span class="comment">// resourcesPath 是配置的存储文件的总目录</span></span><br><span class="line">        String hashDirPath=resourcesPath+<span class="string">&quot;/&quot;</span>+hash;</span><br><span class="line">        File dir=<span class="keyword">new</span> <span class="title class_">File</span>(hashDirPath);</span><br><span class="line">        <span class="keyword">if</span>(!dir.exists())&#123;</span><br><span class="line">            dir.mkdirs();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//创建空文件，名称带seq来标识分块信息</span></span><br><span class="line">        String filePath=hashDirPath+<span class="string">&quot;/&quot;</span>+hash+<span class="string">&quot;_&quot;</span>+seq;</span><br><span class="line">        raf=<span class="keyword">new</span> <span class="title class_">RandomAccessFile</span>(filePath,<span class="string">&quot;rw&quot;</span>);</span><br><span class="line">        <span class="comment">//写入文件流</span></span><br><span class="line">        raf.write(file.getBytes());</span><br><span class="line">    &#125;<span class="keyword">catch</span> (IOException e)&#123;</span><br><span class="line">        log.error(<span class="string">&quot;接收文件切片失败&quot;</span>);</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BusinessException</span>(<span class="number">500</span>,<span class="string">&quot;接收文件切片失败&quot;</span>);</span><br><span class="line">    &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(!Objects.isNull(raf))</span><br><span class="line">                raf.close();</span><br><span class="line">        &#125;<span class="keyword">catch</span> (IOException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>切片传完后的合并接口：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//controller 这里进行了权限限制和日志记录</span></span><br><span class="line"><span class="meta">@PostMapping(&quot;/merge&quot;)</span></span><br><span class="line"><span class="meta">@PreAuthorize(&quot;hasAuthority(&#x27;res_manage&#x27;)&quot;)</span></span><br><span class="line"><span class="meta">@AutoLog(type = ActionLogType.ADD,field = ActionLogField.RESOURCES,description = &quot;上传资料[基础上传]&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ResultMsg&lt;Boolean&gt; <span class="title function_">merge</span><span class="params">(<span class="meta">@RequestBody</span> Resources resources, HttpServletResponse response)</span>&#123;</span><br><span class="line">    AssertUtil.isNull(resources,<span class="string">&quot;缺少参数&quot;</span>);</span><br><span class="line">    resourcesService.uploadMerge(resources,response);</span><br><span class="line">    <span class="keyword">return</span> ResultMsg.success(<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//service实现</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">uploadMerge</span><span class="params">(Resources resources, HttpServletResponse response)</span> &#123;</span><br><span class="line">    <span class="type">String</span> <span class="variable">hash</span> <span class="operator">=</span> resources.getHash();</span><br><span class="line">    <span class="type">String</span> <span class="variable">filename</span> <span class="operator">=</span> resources.getFilename();</span><br><span class="line">    <span class="type">String</span> <span class="variable">type</span> <span class="operator">=</span> resources.getType();</span><br><span class="line">    AssertUtil.hasText(filename,<span class="string">&quot;缺少参数&quot;</span>);</span><br><span class="line">    AssertUtil.hasText(type,<span class="string">&quot;缺少参数&quot;</span>);</span><br><span class="line">    String hashDirPath=resourcesPath+<span class="string">&quot;/&quot;</span>+hash;</span><br><span class="line">    String savePath=StringUtils.hasText(type)?(hashDirPath+<span class="string">&quot;.&quot;</span>+type):hashDirPath;</span><br><span class="line">    File dir=<span class="keyword">new</span> <span class="title class_">File</span>(hashDirPath);</span><br><span class="line">    <span class="keyword">if</span>(!dir.exists())&#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BusinessException</span>(<span class="number">500</span>,<span class="string">&quot;合并文件失败，未找到对应的目录！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//先存储资料信息，以免等待超时</span></span><br><span class="line">    resources.setUploader(UserUtils.getUserId());</span><br><span class="line">    resources.setUploadTime(<span class="keyword">new</span> <span class="title class_">Date</span>());</span><br><span class="line">    resources.setState(Resources.STATE_NORMAL);</span><br><span class="line">    resources.setType(type);</span><br><span class="line">    <span class="built_in">super</span>.save(resources);</span><br><span class="line">    <span class="comment">//合并逻辑放在线程中</span></span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; doMerge(savePath,hashDirPath,hash,dir)).start();</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//执行合并</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">doMerge</span><span class="params">(String savePath,String hashDirPath,String hash,File dir)</span>&#123;</span><br><span class="line">    <span class="comment">//通过FileChannel来实现复制信息流</span></span><br><span class="line">    FileChannel out=<span class="literal">null</span>;</span><br><span class="line">    <span class="comment">//获取目标channel</span></span><br><span class="line">    <span class="keyword">try</span>(FileChannel in=<span class="keyword">new</span> <span class="title class_">RandomAccessFile</span>(savePath,<span class="string">&quot;rw&quot;</span>).getChannel())&#123;</span><br><span class="line">        <span class="comment">//分片索引递增</span></span><br><span class="line">        <span class="type">int</span> index=<span class="number">1</span>;</span><br><span class="line">        <span class="comment">//流开始位置</span></span><br><span class="line">        <span class="type">long</span> start=<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(;;)&#123;</span><br><span class="line">            <span class="comment">//分片文件名</span></span><br><span class="line">            String sliceName=hashDirPath+<span class="string">&quot;/&quot;</span>+hash+<span class="string">&quot;_&quot;</span>+index;</span><br><span class="line">            <span class="type">File</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(sliceName);</span><br><span class="line">            <span class="comment">//到达最后分片 退出循环</span></span><br><span class="line">            <span class="keyword">if</span>(!file.exists())&#123;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">//分片输入流</span></span><br><span class="line">            out=<span class="keyword">new</span> <span class="title class_">RandomAccessFile</span>(sliceName,<span class="string">&quot;r&quot;</span>).getChannel();</span><br><span class="line">            <span class="comment">//写入</span></span><br><span class="line">            in.transferFrom(out,start,start+out.size());</span><br><span class="line">            <span class="comment">//位置增加</span></span><br><span class="line">            start+=out.size();</span><br><span class="line">            out.close();</span><br><span class="line">            out=<span class="literal">null</span>;</span><br><span class="line">            <span class="comment">//分片索引添加</span></span><br><span class="line">            index++;</span><br><span class="line">            file.delete();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//分片合并完毕</span></span><br><span class="line">        in.close();</span><br><span class="line">        <span class="comment">//删除文件夹</span></span><br><span class="line">        dir.delete();</span><br><span class="line">    &#125;<span class="keyword">catch</span> (IOException e)&#123;</span><br><span class="line">        log.error(<span class="string">&quot;文件合并失败！&quot;</span>);</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">        <span class="keyword">throw</span>  <span class="keyword">new</span> <span class="title class_">BusinessException</span>(<span class="number">500</span>,<span class="string">&quot;文件合并失败！&quot;</span>);</span><br><span class="line">    &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (out != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                out.close();</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                e.printStackTrace();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>秒传：</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//controller </span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/fast&quot;)</span></span><br><span class="line"><span class="meta">@PreAuthorize(&quot;hasAuthority(&#x27;res_manage&#x27;)&quot;)</span></span><br><span class="line"><span class="meta">@AutoLog(type = ActionLogType.ADD,field = ActionLogField.RESOURCES,description = &quot;上传资料[秒传]&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ResultMsg&lt;Boolean&gt; <span class="title function_">fastUpload</span><span class="params">(String hash,String name,String notes)</span>&#123;</span><br><span class="line">    AssertUtil.hasText(hash);</span><br><span class="line">    AssertUtil.hasText(name);</span><br><span class="line">    AssertUtil.hasText(notes);</span><br><span class="line">    resourcesService.fastUpload(hash,name,notes);</span><br><span class="line">    <span class="keyword">return</span> ResultMsg.success(<span class="literal">true</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//service实现</span></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">fastUpload</span><span class="params">(String hash, String name, String notes)</span> &#123;</span><br><span class="line">    <span class="comment">//判断是否已存在</span></span><br><span class="line">    <span class="keyword">if</span>(!check(hash))&#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BusinessException</span>(<span class="number">500</span>,<span class="string">&quot;秒传失败！库中不存在对应的文件。&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    QueryWrapper&lt;Resources&gt; wrapper=<span class="keyword">new</span> <span class="title class_">QueryWrapper</span>&lt;&gt;();</span><br><span class="line">    wrapper.eq(<span class="string">&quot;hash&quot;</span>,hash).ne(<span class="string">&quot;state&quot;</span>,Resources.STATE_DELETE);</span><br><span class="line">    <span class="type">Resources</span> <span class="variable">one</span> <span class="operator">=</span> <span class="built_in">super</span>.getOne(wrapper);</span><br><span class="line">    one.setId(<span class="literal">null</span>);</span><br><span class="line">    one.setName(name);</span><br><span class="line">    one.setNotes(notes);</span><br><span class="line">    one.setUploader(UserUtils.getUserId());</span><br><span class="line">    one.setUploadTime(<span class="keyword">new</span> <span class="title class_">Date</span>());</span><br><span class="line">    <span class="built_in">super</span>.save(one);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>至此，文件的切片上传已经完成。文中的一些工具类如AssertUtil断言，AOP日志等省略了，有兴趣可以参考本站的其他博客。</p>
<h2 id="文件下载">文件下载</h2>
<p>文件下载就比上传要轻松一些了。虽然仍然不能直接转Base64字符一股脑扔给前端，但是后端可以通过流式传输，将文件流copy到response里。</p>
<h3 id="前端实现-2">前端实现</h3>
<figure class="highlight html"><table><tr><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">	<span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--这里简略写一些示范代码，仅供参考--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">el-table</span> <span class="attr">:data</span>=<span class="string">&quot;list&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">&quot;id&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;id&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">&quot;name&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;name&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">&quot;hash&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;hash&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">&quot;type&quot;</span> <span class="attr">prop</span>=<span class="string">&quot;type&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">el-table-column</span> <span class="attr">label</span>=<span class="string">&quot;操作&quot;</span>&gt;</span></span><br><span class="line">    			<span class="tag">&lt;<span class="name">el-template</span>&gt;</span></span><br><span class="line">    				<span class="tag">&lt;<span class="name">el-button</span> <span class="attr">size</span>=<span class="string">&quot;mini&quot;</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span>  @<span class="attr">click</span>=<span class="string">&quot;download(scope.row)&quot;</span>&gt;</span>下载<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span><br><span class="line">   				 <span class="tag">&lt;/<span class="name">el-template</span>&gt;</span></span><br><span class="line">    		<span class="tag">&lt;/<span class="name">el-table-column</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">el-table</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"><span class="keyword">export</span> <span class="keyword">default</span>&#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">data</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">return</span>&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">list</span>:[]</span></span><br><span class="line"><span class="language-javascript">        &#125;</span></span><br><span class="line"><span class="language-javascript">    &#125;,</span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">mounted</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="variable language_">this</span>.<span class="title function_">getList</span>()</span></span><br><span class="line"><span class="language-javascript">    &#125;,</span></span><br><span class="line"><span class="language-javascript">    <span class="attr">methods</span>:&#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">async</span> <span class="title function_">getList</span>(<span class="params"></span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//...业务代码</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> &#123;<span class="attr">data</span>:res&#125;=<span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">$http</span>.<span class="title function_">get</span>(<span class="string">&#x27;/xx/xx&#x27;</span>,&#123;<span class="attr">params</span>:&#123;xx,xx&#125;&#125;)</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span>(res.<span class="property">success</span>)</span></span><br><span class="line"><span class="language-javascript">            	<span class="variable language_">this</span>.<span class="property">list</span>=res.<span class="property">data</span></span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">else</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">console</span>.<span class="title function_">error</span>(res.<span class="property">msg</span>)</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">async</span> <span class="title function_">download</span>(<span class="params">row</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> confirmresult =<span class="keyword">await</span> <span class="variable language_">this</span>.$confirm(<span class="string">&#x27;将要下载文件[&#x27;</span>+name+<span class="string">&#x27;]，请确定是否继续？&#x27;</span>,<span class="string">&#x27;提示&#x27;</span>,&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">confirmButtonText</span>:<span class="string">&#x27;确定&#x27;</span>,<span class="attr">cancelButtonText</span>:<span class="string">&#x27;取消&#x27;</span>,<span class="attr">type</span>:<span class="string">&#x27;warning&#x27;</span></span></span><br><span class="line"><span class="language-javascript">            &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span>=&gt;</span>err)</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span>(confirmresult!==<span class="string">&#x27;confirm&#x27;</span>)&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">info</span>(<span class="string">&#x27;已取消下载&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="title function_">downloadFile</span>(row.<span class="property">id</span>,row.<span class="property">hash</span>,row.<span class="property">name</span>,row.<span class="property">type</span>)</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">async</span> downloadFile (id,hash,name,type) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">warning</span>(<span class="string">&#x27;文件[&#x27;</span>+name+<span class="string">&#x27;]下载中，请稍候~&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">const</span> &#123;<span class="attr">data</span>:res&#125;=<span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">$http</span>.<span class="title function_">get</span>(<span class="string">&#x27;res/download&#x27;</span>,&#123;<span class="attr">params</span>:&#123;id,hash&#125;,<span class="attr">responseType</span>: <span class="string">&#x27;blob&#x27;</span>&#125;)</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span>(!res)&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">error</span>(<span class="string">&#x27;下载失败&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">return</span></span></span><br><span class="line"><span class="language-javascript">            &#125;<span class="keyword">else</span>&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//文件名，type为后缀，有的文件可能没有后缀名</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">let</span> filename=(type==<span class="literal">null</span>||type==<span class="string">&quot;&quot;</span>)?<span class="attr">name</span>:(name+<span class="string">&quot;.&quot;</span>+type)</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//构造a标签 通过a标签来下载</span></span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">let</span> url = <span class="variable language_">window</span>.<span class="property">URL</span>.<span class="title function_">createObjectURL</span>(<span class="keyword">new</span> <span class="title class_">Blob</span>([res]))</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">let</span> a = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;a&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">                a.<span class="property">style</span>.<span class="property">display</span> = <span class="string">&#x27;none&#x27;</span></span></span><br><span class="line"><span class="language-javascript">                a.<span class="property">href</span> = url</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//此处的download是a标签的内容，固定写法，不是后台api接口</span></span></span><br><span class="line"><span class="language-javascript">                a.<span class="title function_">setAttribute</span>(<span class="string">&#x27;download&#x27;</span>,filename)</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(a)</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">//点击下载</span></span></span><br><span class="line"><span class="language-javascript">                a.<span class="title function_">click</span>()</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 下载完成移除元素</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">removeChild</span>(a);</span></span><br><span class="line"><span class="language-javascript">                <span class="comment">// 释放掉blob对象</span></span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">window</span>.<span class="property">URL</span>.<span class="title function_">revokeObjectURL</span>(url);</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">this</span>.<span class="property">$message</span>.<span class="title function_">success</span>(<span class="string">&#x27;下载完成~&#x27;</span>)</span></span><br><span class="line"><span class="language-javascript">            &#125;</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">    &#125;</span></span><br><span class="line"><span class="language-javascript">&#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="后端实现-2">后端实现</h3>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//下载文件</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/download&quot;)</span></span><br><span class="line"><span class="meta">@PreAuthorize(&quot;hasAnyAuthority(&#x27;res_manage&#x27;,&#x27;res_download&#x27;)&quot;)</span></span><br><span class="line"><span class="meta">@AutoLog(type = ActionLogType.OTHER,field = ActionLogField.RESOURCES,description = &quot;下载资料&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">download</span><span class="params">(<span class="meta">@RequestParam(&quot;id&quot;)</span>Integer id,<span class="meta">@RequestParam(&quot;hash&quot;)</span>String hash)</span> &#123;</span><br><span class="line">    AssertUtil.isNull(id);</span><br><span class="line">    AssertUtil.hasText(hash);</span><br><span class="line">    <span class="type">ServletRequestAttributes</span> <span class="variable">servletRequestAttributes</span> <span class="operator">=</span> (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();</span><br><span class="line">    HttpServletResponse response=servletRequestAttributes.getResponse();</span><br><span class="line">    <span class="comment">//获取要下载的资源对象，这里是查数据库，可自行根据需要做自己的实现</span></span><br><span class="line">    <span class="type">Resources</span> <span class="variable">resources</span> <span class="operator">=</span> resourcesService.getSaveResource(id,hash);</span><br><span class="line">    <span class="type">FileInputStream</span> <span class="variable">fileInputStream</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="type">BufferedInputStream</span> <span class="variable">bufferedInputStream</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="type">ServletOutputStream</span> <span class="variable">os</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="type">File</span> <span class="variable">fileRes</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>( resources.getSavePath());</span><br><span class="line">        response.reset();</span><br><span class="line">        response.addHeader(<span class="string">&quot;Access-Control-Allow-Origin&quot;</span>, <span class="string">&quot;*&quot;</span>);<span class="comment">//设置响应头</span></span><br><span class="line">        response.addHeader(<span class="string">&quot;Access-Control-Allow-Methods&quot;</span>, <span class="string">&quot;GET, POST, PUT, DELETE&quot;</span>);</span><br><span class="line">        response.addHeader(<span class="string">&quot;Access-Control-Allow-Headers&quot;</span>, <span class="string">&quot;Content-Type&quot;</span>);</span><br><span class="line">        response.setContentType(<span class="string">&quot;application/x-download;charset=utf-8&quot;</span>);</span><br><span class="line">        <span class="comment">//文件名</span></span><br><span class="line">        response.setHeader(<span class="string">&quot;Content-Disposition&quot;</span>, <span class="string">&quot;attachment;filename=&quot;</span> + <span class="keyword">new</span> <span class="title class_">String</span>(resources.getFilename().getBytes(StandardCharsets.UTF_8), <span class="string">&quot;ISO-8859-1&quot;</span>));</span><br><span class="line">        os = response.getOutputStream();</span><br><span class="line">        fileInputStream = <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(fileRes);</span><br><span class="line">        bufferedInputStream = <span class="keyword">new</span> <span class="title class_">BufferedInputStream</span>(fileInputStream);</span><br><span class="line">        <span class="comment">// 复制</span></span><br><span class="line">        IOUtils.copy(bufferedInputStream, os);<span class="comment">//通过IOUtils的copy函数直接将输入文件流的内容复制到输出文件流内</span></span><br><span class="line">        os.flush();</span><br><span class="line">        response.setStatus(HttpServletResponse.SC_OK);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">catch</span> (Exception e)&#123;</span><br><span class="line">        response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(bufferedInputStream != <span class="literal">null</span>)</span><br><span class="line">                bufferedInputStream.close();</span><br><span class="line">        &#125;<span class="keyword">catch</span>(IOException e)&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;bufferedInputStream关闭异常&quot;</span>);</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(fileInputStream != <span class="literal">null</span>)</span><br><span class="line">                fileInputStream.close();</span><br><span class="line">        &#125;<span class="keyword">catch</span>(IOException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            System.out.println(<span class="string">&quot;fileInputStream关闭异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">try</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(os != <span class="literal">null</span>)</span><br><span class="line">                os.close();</span><br><span class="line">        &#125;<span class="keyword">catch</span>(IOException e)&#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            System.out.println(<span class="string">&quot;os关闭异常&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这样文件的流式下载也完成啦。</p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://lienle.gitee.io">Lenl</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://lienle.gitee.io/notes/chunkFile/">https://lienle.gitee.io/notes/chunkFile/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://lienle.gitee.io" target="_blank">LenlBlog</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/SpringBoot/">SpringBoot</a><a class="post-meta__tags" href="/tags/Vue/">Vue</a><a class="post-meta__tags" href="/tags/%E5%88%86%E7%89%87%E4%B8%8A%E4%BC%A0/">分片上传</a></div><div class="post_share"><div class="social-share" data-image="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="/img/wechat.png" target="_blank"><img class="post-qr-code-img" src= "/img/hexo_loading.gif" data-lazy-src="/img/wechat.png" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="/img/alipay.png" target="_blank"><img class="post-qr-code-img" src= "/img/hexo_loading.gif" data-lazy-src="/img/alipay.png" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/bugs/bugsOne/" title="记录BUG与坑--Java相关"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">记录BUG与坑--Java相关</div></div></a></div><div class="next-post pull-right"><a href="/notes/electronVue/" title="Electron+Vue项目搭建"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Electron+Vue项目搭建</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/notes/PdfView/" title="基于pdf.js的前后端分离式PDF文件预览实现"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-08-06</div><div class="title">基于pdf.js的前后端分离式PDF文件预览实现</div></div></a></div><div><a href="/notes/Knife4j/" title="SpringBoot2集成Knife4j完成api文档自动生成"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-05-03</div><div class="title">SpringBoot2集成Knife4j完成api文档自动生成</div></div></a></div><div><a href="/notes/wolf2w/" title="wolf2w项目经验_缓存、持久化与参数解析器"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-04-20</div><div class="title">wolf2w项目经验_缓存、持久化与参数解析器</div></div></a></div><div><a href="/notes/tips/" title="SpringBoot一些优雅的小技巧记录"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-05-03</div><div class="title">SpringBoot一些优雅的小技巧记录</div></div></a></div><div><a href="/notes/wolf2w_2/" title="wolf2w项目经验_站内搜索与接口安全"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-05-01</div><div class="title">wolf2w项目经验_站内搜索与接口安全</div></div></a></div><div><a href="/notes/electronLearn/" title="Electron学习入门笔记"><img class="cover" src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2023-05-06</div><div class="title">Electron学习入门笔记</div></div></a></div></div></div><hr/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div class="vcomment" id="vcomment"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src= "/img/hexo_loading.gif" data-lazy-src="/img/lenl.png" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">Lenl</div><div class="author-info__description">心有所向，日复一日，必有精进~</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">17</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">25</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">8</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/vimianma"><i class="fab fa-github"></i><span>View me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://gitee.com/lienle" target="_blank" title="Gitee"><i class="fa-brands fa-git" style="color: #c71d23;"></i></a><a class="social-icon" href="https://github.com/vimianma" target="_blank" title="Github"><i class="fab fa-github" style="color: #24292e;"></i></a><a class="social-icon" href="mailto:lenl412@163.com" target="_blank" title="Email"><i class="fas fa-envelope" style="color: #4a7dbe;"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">本站意在记录个人生活中的所学所感所想所获；<br/>心有所向，日复一日，必有精进~~~<br>请多多指教~</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0%E6%8A%80%E6%9C%AF"><span class="toc-number">1.</span> <span class="toc-text">实现技术</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0"><span class="toc-number">2.</span> <span class="toc-text">文件上传</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%86%E6%9E%90"><span class="toc-number">2.1.</span> <span class="toc-text">分析</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%89%8D%E7%AB%AF%E5%AE%9E%E7%8E%B0"><span class="toc-number">2.2.</span> <span class="toc-text">前端实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%90%8E%E7%AB%AF%E5%AE%9E%E7%8E%B0"><span class="toc-number">2.3.</span> <span class="toc-text">后端实现</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD"><span class="toc-number">3.</span> <span class="toc-text">文件下载</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%89%8D%E7%AB%AF%E5%AE%9E%E7%8E%B0-2"><span class="toc-number">3.1.</span> <span class="toc-text">前端实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%90%8E%E7%AB%AF%E5%AE%9E%E7%8E%B0-2"><span class="toc-number">3.2.</span> <span class="toc-text">后端实现</span></a></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/notes/dockerNotes/" title="Docker备忘笔记"><img src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Docker备忘笔记"/></a><div class="content"><a class="title" href="/notes/dockerNotes/" title="Docker备忘笔记">Docker备忘笔记</a><time datetime="2024-04-06T13:17:09.000Z" title="发表于 2024-04-06 21:17:09">2024-04-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/notes/mysqlInstall/" title="mysql压缩包方式本地安装"><img src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="mysql压缩包方式本地安装"/></a><div class="content"><a class="title" href="/notes/mysqlInstall/" title="mysql压缩包方式本地安装">mysql压缩包方式本地安装</a><time datetime="2024-01-03T05:33:33.000Z" title="发表于 2024-01-03 13:33:33">2024-01-03</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/notes/PdfView/" title="基于pdf.js的前后端分离式PDF文件预览实现"><img src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="基于pdf.js的前后端分离式PDF文件预览实现"/></a><div class="content"><a class="title" href="/notes/PdfView/" title="基于pdf.js的前后端分离式PDF文件预览实现">基于pdf.js的前后端分离式PDF文件预览实现</a><time datetime="2023-08-06T02:18:26.000Z" title="发表于 2023-08-06 10:18:26">2023-08-06</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/notes/electronVue/" title="Electron+Vue项目搭建"><img src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Electron+Vue项目搭建"/></a><div class="content"><a class="title" href="/notes/electronVue/" title="Electron+Vue项目搭建">Electron+Vue项目搭建</a><time datetime="2023-05-14T02:36:59.000Z" title="发表于 2023-05-14 10:36:59">2023-05-14</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/notes/chunkFile/" title="基于SpringBoot与Vue的大文件分片上传与流式下载"><img src= "/img/hexo_loading.gif" data-lazy-src="https://z4a.net/images/2023/04/22/fcc1d07f3136fe8e818242a6534391c8.md.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="基于SpringBoot与Vue的大文件分片上传与流式下载"/></a><div class="content"><a class="title" href="/notes/chunkFile/" title="基于SpringBoot与Vue的大文件分片上传与流式下载">基于SpringBoot与Vue的大文件分片上传与流式下载</a><time datetime="2023-05-13T13:57:28.000Z" title="发表于 2023-05-13 21:57:28">2023-05-13</time></div></div></div></div></div></div></main><footer id="footer" style="background: -#484847"><div id="footer-wrap"><div class="copyright">&copy;2023 - 2024 By Lenl</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text">Hi, welcome to my blog !</div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><span class="scroll-percent"></span><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox/fancybox.umd.min.js"></script><script src="https://cdn.jsdelivr.net/npm/instant.page/instantpage.min.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><div class="js-pjax"><script>function loadValine () {
  function initValine () {
    const valine = new Valine(Object.assign({
      el: '#vcomment',
      appId: 'dBlOeCLNhBxbSdZO44fRKdBa-gzGzoHsz',
      appKey: 'DCSQoDhPl0UOF7Ix9Imdfd9X',
      avatar: 'monsterid',
      serverURLs: '',
      emojiMaps: "",
      path: window.location.pathname,
      visitor: false
    }, null))
  }

  if (typeof Valine === 'function') initValine() 
  else getScript('https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js').then(initValine)
}

if ('Valine' === 'Valine' || !false) {
  if (false) btf.loadComment(document.getElementById('vcomment'),loadValine)
  else setTimeout(loadValine, 0)
} else {
  function loadOtherComment () {
    loadValine()
  }
}</script></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="true"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div class="no-result" id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></div></body></html>